iT邦幫忙

2023 iThome 鐵人賽

DAY 25
1
Web 3

淺談ZK Rollup系列 第 25

Day 25 - ZK Rollup SP02: Geth基本操作(交易)

  • 分享至 

  • xImage
  •  

在昨天講述了怎麼使用Go-ethereum建立起一條私有鏈,還沒看的可以點這邊觀看,而今天要來看的是當我們有一條私有鏈時,該怎麼用程式跟他互動,當然也是可以透過同樣的方式與現在公開的測試鏈或者以太坊主鏈,那我們就開始吧!我這邊是使用Golang語言做示範,而我這邊Go的版本為1.20.4。

使用Go-ethereum

在一個Golang的模組裡面要引進Go-ethereum就必須進入你的Golang專案資料夾裡面,在command line裡面下以下指令

$ go get github.com/ethereum/go-ethereum

下完指令後,Go-ethereum便會到你的專案模組了!我這邊使用的Go-ethereum版本為1.10.26。

連線

在開始做交易之前,一定要先跟區塊鏈的節點做好連線,由於昨天我們已經弄出一條私有鏈了,使用Go-ethereum裡面的ethclient來進行連線,程式碼如下:

package main

import (
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
	client, err := ethclient.Dial("連線網址,如果是要連你的私有鏈的話,就是 http://127.0.0.1:[你設定的PORT]")
	if err != nil {
		panic(err)
	}
}

這時候可能會發現沒辦法import "github.com/ethereum/go-ethereum/ethclient"進來,那是因為他有一些相依的套件還沒抓進來,可以對command line下以下指令:

$ go mod tidy

透過go mod tidy可以用來獲取所需要的套件。
當做完之後,基本上許多與鏈上的互動都跟這個client做各種不同的展開,使用者個client已經可以做到很多不同的事情,像是查詢各種東西,例如帳戶餘額、帳戶的nonce、鏈上的交易、鏈上特定區塊內容等等。

交易

在做交易的時候,基本上都會圍繞一個帳戶做展開,而我們都知道,在以太坊上一對公私鑰對就可以代表著一個帳戶,而如果一個帳戶要進行交易就要使用他的私鑰進行簽章,所以要進行交易一定要有要交易的人的私鑰,而要將私鑰放入程式中可以使用Go-ethereum裡面的crypto來將私鑰字串轉成他提供的一種PrivateKey的型別,程式碼如下:

package main

import (
    "github.com/ethereum/go-ethereum/crypto"
)

func main() {
    ecdsa_prk, err := crypto.HexToECDSA("你的私鑰16進位數字碼(不含0x字首)")
	if err != nil {
		panic(err)
	}
}

而要產生出一個交易,Go-ethereum有做出一個Transaction的型別,在"github.com/ethereum/go-ethereum/core/types"裡面,所以我們可以用他裡面提供的

func types.NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction

來新增一個Transaction,而以下便是對他帶入參數的解釋:

  • nonce
    • 就是這次交易所要帶入的nonce,而這個nonce數值必須大於等於自己個人帳戶的nonce,以太坊便是運用這個nonce來防止重放攻擊(replay attack)。
  • to
    • 你要轉錢給的那個人的帳戶地址,這邊用的型別是Go-ethereum自己定義的一個Address型別,他是放在"github.com/ethereum/go-ethereum/common"中,而裡面有個func common.HexToAddress(s string) common.Address函數可以透過帶入具有0x為字首的16進位數字字串將他轉換成Address型別。
  • amount
    • 要轉的金錢數量,這邊的單位同樣是wei。
  • gasLimit
    • 這次交易花費的手續費上限,在以太坊上,正常的交易通常會設定為21000。
  • gasPrice
    • 這次的交易手續費一個gas你要付多少錢,我們都知道,在以太坊上,交易手續費的單位都是gas,而基本上一次交易就可以算出該次交易的手續費有多少個gas,而在這邊你可以自己定價,定說一個gas你要花多少錢,但通常你希望你的交易愈快上鏈,這邊手續費設定的價格會愈高,因為礦工會優先挖手續費價格愈高的交易,因為這樣來說對他是比較賺的,如果不知道怎麼填這個的話,可以透過之前連線得到的client,他有一個功能func (*ethclient.Client).SuggestGasPrice(ctx context.Context) (*big.Int, error)會建議你填的gas價格,而這個價格的算法如果都沒調整的話,預設是用最新的20個block的gas價格取平均。
  • data
    • 如果是做正常的交易這邊可以不用帶,當需要帶的時候,通常就是跟合約互動時,這邊才需要帶東西進去。

將這些東西都填好後,就會產生出一個Transaction,但是在讓他上鏈之前要先對他進行簽章,這時候我們要使用的是以下函式:

func types.SignTx(tx *types.Transaction, s types.Signer, prv *ecdsa.PrivateKey) (*types.Transaction, error)

這邊要帶入的是剛剛產生出來的Transaction以及你帳戶的私鑰,還有一個很重要的,便是你要使用什麼規則簽名,在現在的以太坊中,交易使用的簽章方式都是走EIP-155,裡面要帶入這個鏈的chainId,在"github.com/ethereum/go-ethereum/core/types"中有func types.NewEIP155Signer(chainId *big.Int) types.EIP155Signer可以幫你新增出他要的Signer型別,將該帶入的都帶入後,就會產生出一個有簽章的Transaction了,之後透過client將他丟上鏈就大功告成了!


完整的程式碼如下:

package main

import (
	"context"
	"math/big"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
)

func main() {
	client, err := ethclient.Dial("連線網址,如果是要連你的私有鏈的話,就是 http://127.0.0.1:[你設定的PORT]")
	if err != nil {
		panic(err)
	}
    // 如果不知道那條鏈的chainId可以透過這個方式拿到
	chainID, err := client.NetworkID(context.TODO())
	if err != nil {
		panic(err)
	}
	sender_prk, err := crypto.HexToECDSA("你的私鑰16進位數字碼(不含0x字首)")
	if err != nil {
		panic(err)
	}
	nonce, err := client.PendingNonceAt(context.TODO(), crypto.PubkeyToAddress(sender_prk.PublicKey))
	if err != nil {
		panic(err)
	}
	to_addr := common.HexToAddress("你要轉錢給的帳戶地址(含0x字首)")
	amount := big.NewInt(1000000) // 這邊是打算轉1000000wei
	gasLimit := uint64(21000)
	gasPrice, err := client.SuggestGasPrice(context.TODO())
	if err != nil {
		panic(err)
	}
	tx := types.NewTransaction(nonce, to_addr, amount, gasLimit, gasPrice, nil)
	tx, err = types.SignTx(tx, types.NewEIP155Signer(chainID), sender_prk)
	if err != nil {
		panic(err)
	}
	err = client.SendTransaction(context.TODO(), tx)
	if err != nil {
		panic(err)
	}
}

如果成功之後,就代表著交易已經送出去,但不代表著交易上鏈,如果要讓交易上鏈可以透過"github.com/ethereum/go-ethereum/accounts/abi/bind"裡面提供的func bind.WaitMined(ctx context.Context, b bind.DeployBackend, tx *types.Transaction) (*types.Receipt, error)將context、client與剛剛的tx帶入後,他就會等到交易上鏈才會執行接下來的動作,如果是用私有鏈的話,記得要設定讓礦工挖礦才可以讓交易上鏈。


以上就是如何使用Go-ethereum來對以太坊進行交易,而剛剛有稍微提到,與智能合約的互動在以太坊上也是一種交易,那麼也是要使用上述方法來達成嗎?我們要怎麼組合出交易所要帶入的data呢?這個就等到明天再繼續講解了!


上一篇
Day 24 - ZK Rollup SP01: Geth私有鏈
下一篇
Day 26 - ZK Rollup SP03: Geth進階操作(智能合約)
系列文
淺談ZK Rollup30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言